package jp.bgbt.fles.app.rnmodule;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;

import com.common.utils.LogUtil;
import com.common.utils.MPermissionUtils;
import com.common.utils.StringUtils;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;


import androidx.annotation.NonNull;
import androidx.annotation.Nullable;


import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import jp.bgbt.fles.app.MainApplication;
import jp.bgbt.fles.app.R;
import jp.bgbt.fles.app.bean.EventMsg;
import jp.bgbt.fles.app.bean.StrategyDetailsBean;
import jp.bgbt.fles.app.bluetooth.BleCommandUtil;
import jp.bgbt.fles.app.bluetooth.BleConstant;
import jp.bgbt.fles.app.bluetooth.BleDeviceInfo;
import jp.bgbt.fles.app.bluetooth.BleService;
import jp.bgbt.fles.app.bluetooth.BleServiceManager;
import jp.bgbt.fles.app.bluetooth.util.BleConnectUtil;
import jp.bgbt.fles.app.utils.AppUtils;
import jp.bgbt.fles.app.wifi.WifiConnectUtil;

import static android.app.Activity.RESULT_OK;

public class BleModule extends ReactContextBaseJavaModule {

    private DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter;
    private Promise mPromise;
    private Callback mCallback; // 保存回调

    private Disposable scanToConnectDisposable, openDeviceWifiDisposable, connectDeviceWifiDisposable;

    private static final String TAG = "BleModule";
    private static ReactApplicationContext mContext;

    public static final int REQUEST_COARSE_LOCATION = 1;
    public static final int REQUEST_ENABLE_BT = 2;
    public static final int REQUEST_WRITE_EXTERNAL_STORAGE = 3;
    public static final int REQUEST_FINE_LOCATION = 4;
    public static final int REQUEST_LogUtilIN_AUTH = 5;
    public static final int REQUEST_CALL = 6;
    public static final int REQUEST_GPS = 7;

    public boolean mIsScanSkin = false;
    private BleConnectUtil bleConnectUtil;
    private WifiConnectUtil wifiConnectUtil;
    @NonNull
    @Override
    public String getName() {
        return "BleModule";
    }

    private static BleModule instance;
    public static BleModule getInstance(){
        return instance;
    }

    public void senEvent( @Nullable WritableMap params){
        this.eventEmitter.emit("BLE_EVENT",params);
    }

    private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener(){
        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
            super.onActivityResult(activity, requestCode, resultCode, data);
            switch (requestCode) {
                case REQUEST_GPS:
                    LogUtil.d("REQUEST_GPS");
                    checkFineLcation();
                    continueScanBle();
                    break;
                case REQUEST_COARSE_LOCATION:
                    LogUtil.d("REQUEST_COARSE_LOCATION");
                    continueScanBle();
                    break;
                case REQUEST_ENABLE_BT:
                    LogUtil.d("REQUEST_ENABLE_BT");
                    if (resultCode == RESULT_OK) {
                        startScanBle();
                    } else {
                        //蓝牙不可用
                        WritableMap map = Arguments.createMap();
                        map.putString("event","PermissonDenied");
                        map.putString("type","ENABLE_BT");
                        senEvent(map);

                    }
                    break;
            }

        }
    };


    public BleModule(@Nullable ReactApplicationContext reactContext) {
        super(reactContext);
        reactContext.addActivityEventListener(mActivityEventListener);
        mContext = reactContext;
        instance = this;
    }
    public void tryConnectDevice(BluetoothDevice device) {
        if (device != null) {
            String mac = device.getAddress();

            if (!StringUtils.isEmpty(mac) &&
                    mac.replace(":", "").equalsIgnoreCase(device.getName())) {
                BleService service = BleServiceManager.getInstance().getBluetoothService();
                if(service != null) {
                    bleConnectUtil.stopScan();
                    service.connect(mac);
                    LogUtil.d("BleService iconnect" );

                }else{
                    LogUtil.d("BleService is null" );
                    LogUtil.d("bleservice is stop");
                }
            }else{

            }
        }
    }


    private void tryEnableBle() {
        LogUtil.d("tryEnableBle");
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        getCurrentActivity().startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }

    @ReactMethod
    public void init(){
        if(eventEmitter == null){
            eventEmitter = mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
        }

        if(wifiConnectUtil == null){
            wifiConnectUtil = new WifiConnectUtil(MainApplication.getInstance());
        }



        LogUtil.d("--init");
        BleDeviceInfo.getInstance().setShowingResult(false);
        BleServiceManager.getInstance().getBluetoothService();
        if(bleConnectUtil == null){
            bleConnectUtil = new BleConnectUtil(new BleConnectUtil.OnBleConnectListener() {
                @Override
                public void onFindDevice(BluetoothDevice device) {

                    tryConnectDevice(device);
                }

                @Override
                public void requestCoarseLocation() {
                    requestCoarseLocation();
                    LogUtil.d("OnBleConnectListener requestCoarseLocation");
                }

                @Override
                public void onBleDisabled() {
                    tryEnableBle();
                }

                @Override
                public void onScanStarted() {

                }

                @Override
                public void onScanStopped() {
                    LogUtil.d("onScanStopped");
                }

                @Override
                public void onScanStoppedWithTimeout() {
                    LogUtil.d("找不到可用设备");
                    WritableMap map = Arguments.createMap();
                    map.putString("event","NoDeviceFind");
                    senEvent(map);

                }
            });
        }


    }

    @ReactMethod
    public void startScan(boolean isSkin,Promise promise){
        mPromise = promise;
        mIsScanSkin = isSkin;

        requestCoarseLocation();
    }
    /**/
    @ReactMethod
    public void getDeviceInfo(Promise promise){
        boolean isConnect = BleDeviceInfo.getInstance().isDeviceConnected();
        int nurseState = BleDeviceInfo.getInstance().getNurseState();
        String wifiSsid = BleDeviceInfo.getInstance().getRealWifiSSID();

        WritableMap map = Arguments.createMap();
        map.putBoolean("isConnect",isConnect);
        map.putInt("nurseState",nurseState);
        map.putString("wifiSsid",wifiSsid);

        invokeSuccessWithResult(map);
    }

    @ReactMethod
    public void startCareSkin(ReadableMap paramMap){

        String strategy = paramMap.getString("strategy");
        int recordId = paramMap.getInt("recordId");

        StrategyDetailsBean.getInstance().setLedPattern(0);
        BleConstant.writeServiceByte[6] = (byte) 0x14;

        if( paramMap.hasKey("age") ){
            int age = paramMap.getInt("age");
            StrategyDetailsBean.getInstance().setLedAge(age > 60 ? 3 : age > 30 ? 2 : 1);
            StrategyDetailsBean.getInstance().setLedSkinType(1);
        }

        if( paramMap.hasKey("autoModeParam") ){
            ReadableArray array = paramMap.getArray("autoModeParam");
            StrategyDetailsBean.getInstance().confirmLedPattern(array.getInt(0),array.getInt(1));
        }

        List<byte[]> list = BleCommandUtil.getInstance().getQudong(strategy, 4);
        BleCommandUtil.getInstance().sendCommandList(list);
        BleDeviceInfo.getInstance().setRecordId(recordId);
    }

    @ReactMethod
    public void finishCareSkin(){
        BleCommandUtil.getInstance().sendCommand(BleConstant.finishBeauty);
    }

    @ReactMethod
    public void continueCareSkin(){
        int state = BleDeviceInfo.getInstance().getNurseState();
        if(state == BleConstant.NURSE_PAUSED){
            BleCommandUtil.getInstance().sendCommand(BleConstant.continueBeauty);
        }

    }
    @ReactMethod
    public void pauseCareSkin(){
        int state = BleDeviceInfo.getInstance().getNurseState();
        if(state == BleConstant.NURSE_RUNNING){
            BleCommandUtil.getInstance().sendCommand(BleConstant.pauseBeauty);
        }
    }

    @ReactMethod
    public void setLedPattern(int mode){
        StrategyDetailsBean.getInstance().setLedPattern(mode);
        BleConstant.writeServiceByte[4] = (byte) mode;
        BleConstant.writeServiceByte[6] = mode == 0 ? (byte) 0x14 : (byte) 0x0A;
    }
    /*end*/

    private void startScanBle(){
        WritableMap map = Arguments.createMap();
        map.putString("event","startScanBle");
        senEvent(map);
        if (!BleDeviceInfo.getInstance().isDeviceConnected()) {
            bleConnectUtil.stopScan();
            bleConnectUtil.prepareScan();
        }
    }


    public void openDeviceWifiAndGetWifiName(){
        if(BleDeviceInfo.getInstance().isDeviceConnected()){
            BleCommandUtil.getInstance().sendCommand(BleConstant.openWifi);
            BleCommandUtil.getInstance().sendCommand(BleConstant.readWifiAddr);
        }
    }


    public void startScanDeviceWifiAndConnect() {
        BleDeviceInfo.getInstance().setConnectingWifi(false);

        if (!wifiConnectUtil.wifiEnable()) {

        }
        wifiConnectUtil.startScan();
        waitOpenDeviceWifiAndConnectWifiCountDown();
    }

    private void waitOpenDeviceWifiAndConnectWifiCountDown() {
        if(openDeviceWifiDisposable != null && !openDeviceWifiDisposable.isDisposed()) {
            return;
        }
        Observable.interval(2, 1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        openDeviceWifiDisposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        if (  !BleDeviceInfo.getInstance().isDeviceWifiConnected()) {
                            if (aLong == 20) {
                                WritableMap map = Arguments.createMap();
                                map.putString("event","ConnectDeviceWifiTimeOut");
                                senEvent(map);
                                openDeviceWifiDisposable.dispose();
                            } else if(aLong == 6 && !BleDeviceInfo.getInstance().isConnectingWifi()) {
                                // 主动连接指定wifi

                                String ssid = BleDeviceInfo.getInstance().getRealWifiSSID();
                                LogUtil.d("尝试主动连接WIFI，ssid : " + ssid);
                                WritableMap map = Arguments.createMap();
                                map.putString("event","getSSID");
                                map.putString("ssid",ssid);
                                senEvent(map);

                               // wifiConnectUtil.connect(ssid, "", WifiConnectUtil.WifiCipherType.WIFICIPHER_NOPASS);
                                //BleDeviceInfo.getInstance().setConnectingWifi(true);
                            }

                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }


    public void requestCoarseLocation() {
        LogUtil.d("requestCoarseLocation");
        String[] permission = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
        MPermissionUtils.requestPermissionsResult(getCurrentActivity(), REQUEST_GPS,
                permission, new MPermissionUtils.OnPermissionListener() {
                    @Override
                    public void onPermissionGranted() {
                        LogUtil.d("requestCoarseLocation onPermissionGranted");
                        LocationManager locationManager
                                = (LocationManager) MainApplication.getInstance().getSystemService(Context.LOCATION_SERVICE);
                        boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                        if (!gps) {
                            LogUtil.d("requestCoarseLocation 获取不到gps");
                            //请求权限
//                            showRequestPermissionDiaLogUtil(Constant.REQUEST_FINE_LOCATION, true);
                            WritableMap map = Arguments.createMap();
                            map.putString("event","PermissonDenied");
                            map.putString("type","FINE_LOCATION");
                            senEvent(map);
                        } else {
                            continueScanBle();
                        }
                    }

                    @Override
                    public void onPermissionDenied() {
                        LogUtil.d("requestCoarseLocation onPermissionDenied");
//                        showRequestPermissionDiaLogUtil(Constant.REQUEST_GPS, true);
                        WritableMap map = Arguments.createMap();
                        map.putString("event","PermissonDenied");
                        map.putString("type","GPS");
                        senEvent(map);

                    }
                });
    }

    private void checkFineLcation() {
        LogUtil.d("checkFineLcation");
        if (mIsScanSkin && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String[] permission = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
            MPermissionUtils.requestPermissionsResult(getCurrentActivity(), REQUEST_GPS,
                    permission, new MPermissionUtils.OnPermissionListener() {
                        @Override
                        public void onPermissionGranted() {
                            LocationManager locationManager
                                    = (LocationManager) MainApplication.getInstance().getSystemService(Context.LOCATION_SERVICE);
                            boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                            if (!gps) {
//                                showRequestPermissionDiaLogUtil(REQUEST_FINE_LOCATION, true);
                                LogUtil.d("REQUEST_FINE_LOCATION denied");
                                WritableMap map = Arguments.createMap();
                                map.putString("event","PermissonDenied");
                                map.putString("type","FINE_LOCATION");
                                senEvent(map);
                            }
                        }

                        @Override
                        public void onPermissionDenied() {
//                            showRequestPermissionDiaLogUtil(Constant.REQUEST_GPS, true);
                            LogUtil.d("checkFineLcation denied");
                            WritableMap map = Arguments.createMap();
                            map.putString("event","PermissonDenied");
                            map.putString("type","GPS");
                            senEvent(map);
                        }
                    });
        }
    }

    public void continueScanBle() {
        LogUtil.d("continueScanBle");
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (AppUtils.isLocationEnable()) {
                startScanBle();
            } else {
                requestCoarseLocation();
            }
        } else {
            startScanBle();
        }
    }



    private void invokeSuccessWithResult(WritableMap map) {
        if (this.mCallback != null) {
            this.mCallback.invoke(null, map);
            this.mCallback = null;
        } else if (this.mPromise != null) {
            this.mPromise.resolve(map);
        }
    }
    private void invokeError(int resultCode ,WritableMap map) {

        if (this.mCallback != null) {
            this.mCallback.invoke(resultCode,map);
            this.mCallback = null;
        } else if (this.mPromise != null) {
            this.mPromise.reject( String.valueOf(resultCode),map);
        }
    }

}
